#include "filesender.h"
#include <QHostAddress>
#include <QDir>
#include <QMessageBox>

FileSender::FileSender(QObject *parent) :
    QObject(parent)
{
}

FileSender::FileSender(const QString &ip, quint16 port, const QString &fileName,
                       const QByteArray &passid, QObject *parent)
    :QObject(parent), m_sendFileName(fileName), m_passid(passid)
{
    m_totalBytesWritten = 0;
    m_blockSize = 1024 * 1024;
    m_sendFileListIndex = -1;
    m_sendState = SEND_HEAD;
    m_totalFileSize = 0;

    QFileInfo fileInfo(m_sendFileName);
    m_sendFilePath = fileInfo.path() + "/";
    this->addRelaiveFilePath(m_sendFileName, fileInfo.fileName());

    qDebug() << QString("passid = %1, fileLength = %2, fileNumber = %3")
                .arg(QString(m_passid)).arg(m_totalFileSize).arg(m_sendFileList.size());
    //开始计时
    m_startTime = QDateTime::currentDateTime();

    m_socket = new QTcpSocket(this);
    m_socket->connectToHost(QHostAddress(ip), port);
    connect(m_socket, &QTcpSocket::stateChanged, this, &FileSender::onStateChanged);
}

void FileSender::onStateChanged(QAbstractSocket::SocketState socketState)
{
    switch (socketState) {
        case QAbstractSocket::UnconnectedState:
            if(m_sendFileListIndex != m_sendFileList.size()){
                this->sendFail("连接已断开!");
            }
            break;
        case QAbstractSocket::ConnectedState:
            {
                FilesInfo filesInfo;
                filesInfo.m_filesSize = m_totalFileSize;
                filesInfo.m_filesNumber = m_sendFileList.size();
                filesInfo.m_passidSize = m_passid.size();
                m_socket->write((char*)&filesInfo, sizeof(filesInfo));
                m_socket->write(m_passid);
                qDebug() << QString("passid = %1, fileLength = %2, fileNumber = %3")
                            .arg(QString(m_passid)).arg(m_totalFileSize).arg(m_sendFileList.size());
                connect(m_socket, &QTcpSocket::bytesWritten, this, &FileSender::onBytesWritten);
            }
            break;

        default:
            break;
//        case QAbstractSocket::HostLookupState:
//        case QAbstractSocket::ConnectingState:
//        case QAbstractSocket::BoundState:
//        case QAbstractSocket::ClosingState:
//        case QAbstractSocket::ListeningState:
//            qDebug() << __FUNCTION__ << "QAbstractSocket::HostLookupState";
//            qDebug() << __FUNCTION__ << "QAbstractSocket::ConnectingState";
//            qDebug() << __FUNCTION__ << "QAbstractSocket::ClosingState";
//            break;

    }
}

void FileSender::onBytesWritten(qint64 bytes)
{
    Q_UNUSED(bytes);

    switch (m_sendState) {
    case SEND_HEAD:
    {
        ++m_sendFileListIndex;
        if(m_sendFileListIndex >= m_sendFileList.size()){
            this->sendOk();
            return;
        }
        QString fileName = m_sendFilePath + m_sendFileList.at(m_sendFileListIndex);
        QFileInfo fileInfo(fileName);
        //转换成Utf8格式
        QByteArray sendFileName = m_sendFileList.at(m_sendFileListIndex).toUtf8();
        FileHead fileHead;
        fileHead.m_fileNameSize = sendFileName.size();
        if(fileInfo.isDir()){
            fileHead.m_fileType = FileHead::TYPE_DIR;
            fileHead.m_fileContentSize = 0;
        }
        else{
            //重置当前读写进度
            m_currentFileSize = fileInfo.size();
            m_currentFileBytesWritten = 0;
            //写入头部信息
            fileHead.m_fileType = FileHead::TYPE_FILE;
            fileHead.m_fileContentSize = fileInfo.size();
            m_file.setFileName(fileName);
            if(!m_file.open(QIODevice::ReadOnly)){
                sendFail(QString("打开文件: %1 失败").arg(fileName));
            }
            m_sendState = SEND_CONTENT;
        }
        m_socket->write((char*)&fileHead, sizeof(fileHead));
        m_socket->write(sendFileName);

    }

        break;
    case SEND_CONTENT:
    {
        int writeSize = qMin(m_blockSize, m_currentFileSize - m_currentFileBytesWritten);
        m_socket->write(m_file.read(writeSize));
        m_currentFileBytesWritten += writeSize;
        m_totalBytesWritten += writeSize;
        if(m_currentFileBytesWritten == m_currentFileSize){
            m_file.close();
            m_sendState = SEND_HEAD;
        }
    }
        break;

    default:
        this->sendFail("onBytesWritteen()跳转到错误状态");
        break;
    }
}



void FileSender::addRelaiveFilePath(const QString &absoluteFilePath, const QString &relaiveFilePaht)
{
    QFileInfo fileInfo(absoluteFilePath);
    //如果是隐藏文件或者链接类则跳过
    if(fileInfo.fileName() == "." || fileInfo.fileName() == ".." ||
            fileInfo.isHidden() || fileInfo.isSymLink())
    {
        qDebug() << absoluteFilePath << "跳过!";
        return;
    }
    //把相对文件路径添加到队列中
    m_sendFileList.append(relaiveFilePaht);
    if(fileInfo.isDir()){
        qDebug() << absoluteFilePath << "是目录!";
        //获取目录中所有文件，并递归添加到队列中
        QStringList list = QDir(absoluteFilePath).entryList();
        for(int i = 0; i < list.count(); ++i){
            addRelaiveFilePath(absoluteFilePath + "/" + list.at(i),
                               relaiveFilePaht + "/" + list.at(i));
        }
    }
    else{
        m_totalFileSize += fileInfo.size();
    }
}

void FileSender::sendFail(const QString &failInfo)
{
    m_socket->close();
    QMessageBox::warning(nullptr, "发生错误", failInfo);
}

void FileSender::sendOk()
{
    m_socket->close();
    QMessageBox::information(nullptr, "发送完成",
                             QString("发送文件: %1 完毕!一共发送%2 byt数据, %3 个文件")
                             .arg(m_sendFileName)
                             .arg(m_totalBytesWritten)
                             .arg(m_sendFileList.size()));
}
